﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Peak.Core
{
  public class SprintStory : EntityWithBusinessRules
  {
    public virtual Story Story { get; set; }
    public virtual IList<Task> Tasks { get; set; }
    public virtual Sprint Sprint { get; set; }
    public virtual int OpenedTaskCount { get; set; }

    private StoryStatus _status;
    public virtual StoryStatus Status
    {
      get
      {
        return _status;
      }
      set
      {
        if (!RulesEnabled())
        {
          _status = value;
          return;
        }

        if(_status != value)
        {
          if (_status == StoryStatus.ToDo)
          {
            StartDate = DateTime.Now;
          }

          if (value == StoryStatus.Done)
          {
            EndDate = DateTime.Now;            
          }

          if(value != StoryStatus.ToDo)
          {
            Story.Status = value;
          }

          _status = value;
        }
      }
    }

    private DateTime? _startDate;
    public virtual DateTime? StartDate
    {
      get
      {
        return _startDate;
      }
      set
      {
        if (_startDate != value)
        {
          if (Story != null && Story.StartDate == null && RulesEnabled())
          {
            Story.StartDate = value;
          }
          _startDate = value;
        }
      }
    }

    private DateTime? _endDate;
    public virtual DateTime? EndDate
    {
      get
      {
        return _endDate;
      }
      set
      {
        if (_endDate != value)
        {
          if (Story != null && (Story.EndDate == null || Story.EndDate < value) && RulesEnabled())
          {
            Story.EndDate = value;
          }
          _endDate = value;
        }
      }
    }

    private TimeSpan _remainingEffort;
    public virtual TimeSpan RemainingEffort
    {
      get
      {
        return _remainingEffort;
      }
      set
      {
        if (_remainingEffort != value)
        {
          if (RulesEnabled() && Sprint != null)
          {
            Sprint.RemainingEffort += value - _remainingEffort;
          }          

          _remainingEffort = value;
        }
      }
    }

    private TimeSpan _currentEffort;
    public virtual TimeSpan CurrentEffort
    {
      get
      {
        return _currentEffort;
      }
      set
      {
        if (_currentEffort != value)
        {
          if (RulesEnabled() && Sprint != null)
          {
            Sprint.CurrentEffort += value - _currentEffort;
          }          

          _currentEffort = value;
        }
      }
    }

    private double _storyPoints;
    public virtual double StoryPoints
    {
      get
      {
        return _storyPoints;
      }
      set
      {
        _storyPoints = value;        
      }
    }

    public SprintStory()
    {
      Tasks = new List<Task>();
      Status = StoryStatus.ToDo;
    }

    public virtual void AddTask(Task task)
    {
      if (task.RemainingEffort == TimeSpan.Zero && Sprint != null && Sprint.Status != SprintStatus.Planning)
        throw new NotEstimatedException();

      RemainingEffort += task.RemainingEffort;
      CurrentEffort += task.CurrentEffort;
      task.SprintStory = this;
      task.Project = Story.Project;
      if (task.Status != TaskStatus.Done)
        OpenedTaskCount++;
      Tasks.Add(task);

      CheckStatus();
    }

    public virtual void RemoveTask(Task task)
    {
      RemainingEffort -= task.RemainingEffort;
      CurrentEffort -= task.CurrentEffort;
      task.SprintStory = null;
      task.Project = null;
      if (task.Status != TaskStatus.Done)
        OpenedTaskCount--;
      Tasks.Remove(task);

      CheckStatus();
    }

    public virtual void CheckStatus()
    {
      if (AllFinished())
      {
        Status = StoryStatus.Verify;
      }
      else
      {
        if (Tasks.FirstOrDefault(t => t.Status != TaskStatus.ToDo) == null)
        {
          Status = StoryStatus.ToDo;
        }
        else
        {
          Status = StoryStatus.InProgress;
        }
      }
    }

    public virtual bool AllFinished()
    {
      return OpenedTaskCount == 0;
    }

    public virtual bool AllEstimated()
    {
      foreach (Task task in Tasks)
      {
        if (task.RemainingEffort == TimeSpan.Zero && task.Status == TaskStatus.ToDo)
          return false;
      }
      return true;
    }
  }
}
